
#include "Dispatcher.h"
#include <sys/epoll.h>
#include "Channel.h"
#include "Log.h"
#define MAXEVENTS 1024
struct EpollData
{
    int epfd;
    // 这个用来接受数据那个数组
    struct epoll_event *events;
};

static void *epollinit(); // Dispacherdata

static int epollAdd(struct Channel *channel, struct EventLoop *eventLoop);

static int epollRemove(struct Channel *channel, struct EventLoop *eventLoop);

static int epollModify(struct Channel *channel, struct EventLoop *eventLoop);

static int epollDispatch(struct EventLoop *eventLoop, int timeout);

static int epollClear(struct EventLoop *eventLoop);

/// @brief 对add modify remove 的封装
/// @param channel
/// @param eventLoop
/// @param op
/// @return
static int epollctl(struct Channel *channel, struct EventLoop *eventLoop, int op);

// 如何和Dispatcher关联
struct Dispatcher EpollDispatcher =
    {
        epollinit,
        epollAdd,
        epollRemove,
        epollModify,
        epollDispatch,
        epollClear};

static void *epollinit()
{
    struct EpollData *data = (struct EpollData *)malloc(sizeof(struct EpollData));
    if (!data)
    {
        perror("malloc");
        exit(EXIT_FAILURE);
    }
    data->epfd = epoll_create(1);
    // Debug("epoll fd %d",data->epfd);
    if (data->epfd == -1)
    {
        perror("epoll_create");
        exit(0);
    }

    data->events = (struct epoll_event *)calloc(MAXEVENTS, sizeof(struct epoll_event));
    if (!data->events)
    {
        perror("calloc");
        close(data->epfd);
        free(data);
        exit(EXIT_FAILURE);
    }

    return data;
}

/// @brief
/// @param channel  channel 的读或者写是我们自己定义的，跟linux的不一样
/// @param eventLoop
static int epollAdd(struct Channel *channel, struct EventLoop *eventLoop)
{
    int ret = epollctl(channel, eventLoop, EPOLL_CTL_ADD);
    if (ret == -1)
    {
        perror("epoll_ctl");
        exit(0);
    }
    return ret;
}

static int epollRemove(struct Channel *channel, struct EventLoop *eventLoop)
{
    int ret = epollctl(channel, eventLoop, EPOLL_CTL_DEL);
    if (ret == -1)
    {
        perror("epoll_remove");
        exit(0);
    }
    // 通过channel释放对应的TcpConnection 的资源
    channel->destoryCallBack(channel->arg);
    return ret;
}

static int epollModify(struct Channel *channel, struct EventLoop *eventLoop)
{
    int ret = epollctl(channel, eventLoop, EPOLL_CTL_MOD);
    if (ret == -1)
    {
        perror("epoll_modify");
        exit(0);
    }
    return ret;
}

// 我在想他这里为什什么要进行转换，说传过来的是void* 类型的
static int epollDispatch(struct EventLoop *eventLoop, int timeout)
{
    struct EpollData *data = (struct EpollData *)eventLoop->DispatcherData;

    int count = epoll_wait(data->epfd, data->events, MAXEVENTS, timeout * 1000); // 传进来的事件是ms

    for (int i = 0; i < count; i++)
    {
        // 注意这是一个一个的
        int events = data->events[i].events;

        // 现在这是还是传的fd // 这里是联合体的那个fd 定义在这里
        // typedef union epoll_data {
        //        void        *ptr;
        //        int          fd;
        //        uint32_t     u32;
        //        uint64_t     u64;
        //    } epoll_data_t;

        //    struct epoll_event {
        //        uint32_t     events;      /* Epoll events */
        //        epoll_data_t data;        /* User data variable */
        //    };
        int fd = data->events[i].data.fd;

        // 当对端断开连接  第二个 对端断开连接 然后我们还在给对方发数据
        if (events & EPOLLERR || events & EPOLLHUP)
        {
            // 错误事件
            // 这个channel 后续处理
            // epollRemove(Channel,eventLoop);
            continue;
        }
        if (events & EPOLLIN)
        {
            // 读事件 具体怎么说呢 通过一种映射 fd-> channel* 封装在channelMap 里面  然后channel 里面封装了方法的
            eventActivate(eventLoop, fd, ReadEvent);
        }
        if (events & EPOLLOUT)
        {
            eventActivate(eventLoop, fd, WriteEvent);
        }
    }
    return 0;
}

static int epollClear(struct EventLoop *eventLoop)
{
    struct EpollData *data = (struct EpollData *)eventLoop->DispatcherData;
    // 创建的数组
    if (data)
    {
        if (data->events)
        {
            free(data->events);
        }
        if (data->epfd != -1)
        {
            close(data->epfd);
        }
        free(data);
    }
    return 0;
}

static int epollctl(struct Channel *channel, struct EventLoop *eventLoop, int op)
{
    struct EpollData *data = (struct EpollData *)eventLoop->DispatcherData;
    if (!data)
    {
        perror("DispatcherData is NULL");
        return -1;
    }
    struct epoll_event ev;
    memset(&ev, 0, sizeof(struct epoll_event));
    ev.data.fd = channel->fd;
    // 设置事件events
    int events = 0;
    if (channel->event & ReadEvent)
    {
        events |= EPOLLIN;
    }
    // 不能同时判断读或者写
    if (channel->event & WriteEvent)
    {
        events |= EPOLLOUT;
    }

    ev.events = events;
    // 添加到epoll中
    int ret = epoll_ctl(data->epfd, op, channel->fd, &ev);
    return ret;
}